package megrez.job.custom.component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import megrez.job.common.JobException;
import megrez.job.custom.utils.TaskStateException;

/**
 * 任务注册
 * 
 * @author Lucky Yang
 * @since 2.6.9
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TaskRegistrar implements DisposableBean {
    private final TaskScheduler taskScheduler;
    private final TaskService taskService;

    public synchronized void register(Task task) {
        if (log.isDebugEnabled()) {
            log.debug("Task is registering: {}", task);
        }

        if (ScheduledTaskContainer.isStarted(task)) {
            throw new TaskStateException();
        }
        try {
            ScheduledTask scheduleTask = new ScheduledTask(task, taskService);
            CronTask cronTask = new CronTask(scheduleTask, task.getConfig().getCronExpression());
            ScheduledFuture<?> future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
            ScheduledFutureTaskHolder holder = new ScheduledFutureTaskHolder(scheduleTask, future);
            ScheduledTaskContainer.put(task, holder);

            holder.start();
        } catch (Exception e) {
            throw new JobException(e);
        }
    }

    public synchronized void unregister(Task task) {
        if (log.isDebugEnabled()) {
            log.debug("Task is unregistering: {}", task);
        }

        if (ScheduledTaskContainer.isStopped(task)) {
            throw new TaskStateException();
        }

        ScheduledTaskContainer.get(task).ifPresent(ScheduledFutureTaskHolder::stop); 
    }

    public List<Task> unregisterAll() {
        List<Task> stoppedTaskList = new ArrayList<>();
        ScheduledTaskContainer.loopInContainer(entry -> {
            Task task = entry.getKey();
            if (ScheduledTaskContainer.isStopped(task)) {
                return;
            }

            unregister(task);
            stoppedTaskList.add(task);
        });
        return stoppedTaskList;
    }

    @Override
    public void destroy() {
        List<Task> stoppedTaskList = unregisterAll();

        log.info("Total task is {}, {} tasks stopped successfully ", ScheduledTaskContainer.size(), stoppedTaskList.size());
        if (log.isDebugEnabled() && !stoppedTaskList.isEmpty()) {
            log.debug("Stopped task list: {}", stoppedTaskList);
        }
    }

}
